home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Publishing
/
ImagePortfolio
/
Source
/
objectThreadPerform.h
< prev
next >
Wrap
Text File
|
1994-04-01
|
7KB
|
119 lines
// -------------------------------------------------------------------------------------
// objectThreadPerform.m
// Martin D. Flynn, NeXT Computer, Inc.
//
// This category of Object provides a general solution for thread support which includes
// a solution for allowing threads to communicate with the window/event manager.
//
// Using 'forkPerform:detach:', a thread can be created to perform some action in the
// background while the window manager (main thread) is free to handle events.
//
// In addition to creating new threads, support is provided to allow a forked thread to
// communicate with the main thread to tell it to execute actions, such as drawing in a
// view, and even returning values. This is accomplished through calls to
// 'mainThreadPerform:with:wait:'. This method can be called from any thread, making sure
// that the main thread is the only thread that will process the specified action. These
// methods are object independent, meaning that 'mainThreadPerform:wait:' can be sent to
// ANY object from ANY thread. For instance, a forked thread could set the title of some
// button with the following:
// [someButtonId mainThreadPerform:@selector(setTitleNoCopy:) with:aStaticTitle wait:NO];
// (A forked thread should not try to set the title of a button itself, or execute any
// other method that causes drawing to occur. This is because it has no way of knowing
// what drawing may already be occurring, and it may in fact cause drawing to occur in a
// view other than where it was originally intended.)
//
// The return value can also be obtained from the method executed from the main thread by
// setting 'wait:YES'. For example, to wait for a return value from a method executed
// from the main thread you could issue the following message:
// rtn = [myObject mainThreadPerform:@selector(showErrorPanel:) with:errorMsg wait:YES];
// The value that 'showErrorPanel:' returned in the main thread would be returned to the
// calling thread. This is helpful when a thread wishes to display an error panel, then
// act on the response from the user.
//
// -------------------------------------------------------------------------------------
#import <mach/cthreads.h>
#import <objc/Object.h>
// -------------------------------------------------------------------------------------
// thread perform macros (Object category enhancements)
// (see 'mainThreadPerform:wait:' below for more informaiton)
#define isMainTHREAD [Object isMainThread]
#define _cmdPERFORM(P) [self mainThreadPerform:_cmd with:(id)(P) wait:NO]
#define _cmdPERFORMw(P) [self mainThreadPerform:_cmd with:(id)(P) wait:YES]
#define _cmdINVOKE(P) { if (!isMainTHREAD) return _cmdPERFORM(P); }
#define _cmdINVOKEw(P) { if (!isMainTHREAD) return _cmdPERFORMw(P); }
// -------------------------------------------------------------------------------------
@interface Object(ThreadPerform)
// -------------------------------------------------------------------------------------
+ initThreadSupport;
// This initialization will occur automatically when 'forkPerform:...' is executed from
// the main thread. You may call this method to explicitly initialize this thread
// support prior to calling 'forkPerform:...'
//
// -------------------------------------------------------------------------------------
+ (BOOL)isMainThread;
- (BOOL)isMainThread;
// These methods return true if called from the main thread, else they return false.
// Valid only after a call to 'initThreadSupport', or 'forkPerform:...', has been made.
//
// -------------------------------------------------------------------------------------
- perform:(SEL)selector with:arg1 with:arg2 argCount:(int)argCount;
// This method is a shell for the individual 'perform:[with:[with:]]' with the specified
// number of arguments.
// An argCount of 0 would send [self perform:selector];
// An argCount of 1 would send [self perform:selector with:arg1];
// An argCount of 2 would send [self perform:selector with:arg1 with:arg2];
// Any other value for argCount will be ignored.
//
// -------------------------------------------------------------------------------------
- mainThreadPerform:(SEL)aSelector wait:(BOOL)waitFlag;
- mainThreadPerform:(SEL)aSelector with:anArg wait:(BOOL)waitFlag;
- mainThreadPerform:(SEL)aSelector with:anArg0 with:anArg1 wait:(BOOL)waitFlag;
// This method will cause aSelector to be executed by the main thread. If the calling
// thread is not the main thread, this method sends an aSelector message through a Mach
// port to the main thread to be executed. If the calling thread is the main thread,
// then the aSelector message is sent directly. If waitFlag is true, then the calling
// thread will be suspended until the main thread completes the execution of the message,
// and the return value will be that of the aSelector message executed from the main
// thread. If waitFlag is false, then this method returns (id)nil.
// Macros: _cmdPERFORM(anArg) /* [self mainThreadPerform:_cmd with:anArg wait:NO] */
// _cmdPERFORMw(anArg) /* [self mainThreadPerform:_cmd with:anArg wait:YES] */
// _cmdINVOKE(anArg) /* { if (!isMainTHREAD) return _cmdPERFORM(anArg); } */
// _cmdINVOKEw(anArg) /* { if (!isMainTHREAD) return _cmdPERFORMw(anArg); } */
//
// Note on use of _cmdINVOKE(anArg) and _cmdINVOKEw(anArg) :
// To guarentee that a method is executed from the main thread the method need only
// include '_cmdINVOKE(anArg);' at the beginning of the method. When this macro is
// executed, it checks to see if it is the main thread. If it is not then it is sent
// to the main thread and the macro causes the method to return. If it is executed
// from the main thread, as it would be after being sent to _cmdPERFORM(anArg), then
// the method is allowed to execute normally. Using _cmdINVOKEw(anArg) performs
// the same as _cmdINVOKE(anArg) except that it waits for the main thread to finish
// execution of the method before returning. It is important to note that if this
// method is implemented in a subclass, it is important that the subclass implementation
// duplicate the the call to the macro at the beginning of the method. Otherwise
// unpredictable results may occur.
//
// Example use of _cmdINVOKE(anArg);
// - setButtonState:(BOOL)newState
// {
// _cmdINVOKE(newState);
// [myButton setState:newState];
// // ... other code here ...
// return self;
// }
//
// -------------------------------------------------------------------------------------
- (cthread_t)forkPerform:(SEL)aSelector detach:(BOOL)detach;
- (cthread_t)forkPerform:(SEL)aSelector with:anArg detach:(BOOL)detach;
- (cthread_t)forkPerform:(SEL)aSelector with:anArg0 with:anArg1 detach:(BOOL)detach;
// This method creates a new thread in which the aSelector message is executed. The
// cthread handle for the created thread is returned if 'detach:NO' was specified, and
// normal cthread functions may be performed on this handle. Nil is returned if
// 'detach:YES' was specified, since there is no guarantee that the returned value would
// ever be valid (ie. The thread could terminate before you use the handle).
//
// -------------------------------------------------------------------------------------
@end